package cn.tedu.v5;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * Version 5 多人聊天+QQ聊天+消息转发
 * 功能：登录  + 聊天  【退出】
 * 登录步骤：1.私有化属性，保存账号与密码---userDataBase
 *         2.构造器，创建两个用户名与账号
 *         3.处理多个客户端，加私有化属性：账号、密码
 */

    public class Server {
    private ServerSocket serverSocket;
    private static final  Integer PORT=5588;
    private List<PrintWriter> allOut=new ArrayList<>();
    //1.私有化属性--保存账号与密码
    private Map<String,String> userDataBase;
    public Server() {
    try {
    serverSocket = new ServerSocket(PORT);
    //2.Server对象启动--main方法--
    // 创建服务器之初，完成对象账号与密码赋值
    userDataBase=new HashMap<>();
    userDataBase.put("吵吵","19890411");
    userDataBase.put("嘻嘻","20051222");
    } catch (BindException e) {
    System.out.println("端口号重复申请，建议换个端口号");
    } catch (IOException e) {
    System.out.println("申请端口号失败...");
    }
    }

    public void start() {
    try {
    while (true) {
    System.out.println("----等待客户端链接----");
    Socket socket = serverSocket.accept();
    System.out.println(socket+"12345");
    String ip = socket.getInetAddress().getHostAddress();
    System.out.println(ip + "客户端链接成功了~~");
    new Thread(new ClientHandler(socket)).start();
    }
    } catch (IOException e) {
    System.out.println("服务器端通讯断开了");
    } finally {
    if(serverSocket!=null&&!serverSocket.isClosed()){
    try {
    serverSocket.close();
    } catch (IOException e) {
    System.out.println("服务器关闭失败");
    }
    }
    }
    }

    public static void main(String[] args) {
    new Server().start();
    }
    private synchronized void broadcastMessage(String message) {
    for (PrintWriter pw:allOut){
    pw.println("消息广播"+message);
    }
    }
    private class ClientHandler implements Runnable {
    private Socket socket;
    private String ip;
    private BufferedReader br;
    private PrintWriter pw;
    //3.很多客户端都具备账号密码
    private String username;
    private String password;
    public ClientHandler(Socket s) {
    this.socket = s;
    ip = socket.getInetAddress().getHostAddress();
    try {
    br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF8"));
    pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF8")), true);
    synchronized (allOut) {
    allOut.add(pw);
    }
    } catch (IOException e) {
    System.out.println("客户端断开通讯");
    }
    }
    //4.4.1 封装判断账号与密码是否正确的方法--Login
    private boolean Login(String user,String pass){
    //userDataBase.containsKey(user)  判断账号存在
    return userDataBase.containsKey(user)&&userDataBase.get(user).equals(pass);
    }
    //5.账号与密码验证成功--登录--聊天：读写功能---封装方法handlerChat
    private void handlerChat() {
    new Thread(() -> {
    try {
    String message;
    while ((message = br.readLine()) != null) {
        //System.out.println("打桩"+br);
    System.out.println("客户端说" + message);
    System.out.println("服务器请输入：");
    broadcastMessage(message);
    }
    } catch (IOException e) {
    System.out.println("客户端读入失败！");
    e.printStackTrace();
    }
    }).start();
    Scanner input = new Scanner(System.in);
    while (true) {
    System.out.println(ip + "恭喜你抽中五百万！");
    String say = input.nextLine();
    pw.println("服务器说"+say);
    }
    }
    public void run() {
    try {
    //4.目的：启动客户端与服务器链接
    //假设：一个客户端连接上了，服务器应该怎么处理
    //4.1  登录验证   【服务器与客户端交互问题】
    pw.println("请输入用户名：");//发给客户端
    username=br.readLine(); //客户端发来的账号
    //4.2  密码验证
    pw.println("请输入密码：");//发给客户端
    password=br.readLine();//读入客户端输入的密码
    //4.3  验证账号与密码  【服务器与客户端交互问题】
    //4.4  账号很多情况：封装方法---功能：判断账号与密码是否准确
    if (Login(username,password)) {//判断Login 为true 账号与密码正确
        System.out.println("11111");
    pw.println("登陆成功，欢迎进入聊天室~");
    System.out.println("22222");
    //聊天  4.5 封装方法--登录成功--开始聊天：读写功能--HandlerChat
    handlerChat();
    }else{
    pw.println("登陆失败，账用户名或密码不正确！");
    socket.close();//登录失败，关闭连接
    }
    } catch (NullPointerException e) {
    System.out.println("IO流传入对象，有对象为null，立马核对，建议：查看try块中对象可能赋值为null");
    }catch (IOException e) {
    System.out.println("服务器端断开连接");
    } finally {
    synchronized (allOut) {
    allOut.remove(pw);
    }
    if (br!=null)
    try {
    br.close();
    } catch (IOException e) {
    System.out.println("结束通讯：关闭失败！");
    }
    if (pw != null)
    pw.close();
    if (socket!= null&&!socket.isClosed())
    try {
    socket.close();
    } catch (IOException e) {
    System.out.println("通讯关闭，关闭失败");
    }
    }
    }
    }
    }

